﻿#if UNITY_EDITOR
using Game;
using Game.Editor;
using Game.Global.Helper;
using System;
using System.Collections;
using UnityEditor;
using UnityEngine;

/// <summary>
/// 在Terrain或指定Tag的物体上放置新的物体
/// </summary>
//自定义Tset脚本
[CustomEditor(typeof(Editor_ObjData))]
[ExecuteInEditMode]
public class Editor_ObjPlacer : UnityEditor.Editor
{
    /// <summary>
    /// 数据存储的Manager
    /// </summary>
    Editor_ObjData editorDataManager;
    SceneObjGroupManager objGroupManager;

    /// <summary>
    /// 编辑器激活此脚本所在物体时使用
    /// </summary>
    void OnEnable()
    {
        editorDataManager = (Editor_ObjData)target;
        editorDataManager.InitObjData();
        objGroupManager = editorDataManager.Editor_GetObjGroupManager();

        //加入监听视图更新：
        SceneView.onSceneGUIDelegate += OnMapEditorSceneUpdate;
    }

    public void OnDisable()
    {
        SceneView.onSceneGUIDelegate -= OnMapEditorSceneUpdate;
        
    }

    /// <summary>
    /// Editor 定制Inspector的GUI绘制事件
    /// </summary>
    public override void OnInspectorGUI()
    {
        GUILayout.BeginHorizontal();
        //总设定
        if (GUILayout.Button("Setting window", GUILayout.MaxWidth(120)))
        {
            Editor_ObjSettingWindow win = EditorWindow.GetWindow<Editor_ObjSettingWindow>();
            win.Init(editorDataManager);
            win.Show();
        }

        if(GUILayout.Button("Generate previews",GUILayout.MaxWidth(120)))
        {
            Debug.Log("Will generate previews of prefabs to Resources.");
            objGroupManager.Editor_GenPreviewForPrefabs();
        }
        GUILayout.EndHorizontal();

        //另外其他设定的视图
        //_DrawLayerSettingView();

        GUILayout.Space(16);

        DrawMapPaintBlockView();
        
        _DrawEndSpace();

    }

    /// <summary>
    /// EditorData中的设定信息中游戏物体的引用，从此妈妈再也不用担心我临时空间多次分配问题
    /// </summary>
    GameObject[] tmp_go_prefs;

    /// <summary>
    /// 当前选择绘制的物体
    /// </summary>
    GameObject currBlockToPaint;

    /// <summary>
    /// 当前绘制的物体在数组中的下标
    /// </summary>
    int currBlocksIndexChoose = -1;

    private void DrawMapPaintBlockView()
    {
        //--选择绘制目标的Tag
        editorDataManager.targetObjTagToPaintOn = EditorGUILayout.TagField("0. Tag of the object to paint on:",editorDataManager.targetObjTagToPaintOn);
        GUILayout.Space(16);

        //--设置物体：
        GUILayout.Label("1.Set your Obj:");
        if (GUILayout.Button("Set prefabs:", GUILayout.MinHeight(32)))
        {
            PickItemWindows pickItemWindow = EditorWindow.GetWindow<PickItemWindows>();
            pickItemWindow.Init(editorDataManager);
        }

        #region 设置多个砖块预设体的显示：
        GUILayout.Space(16);
        
        GUILayout.Label("2.Pick & Draw:");

        //Draw selection:
        tmp_go_prefs = editorDataManager.Editor_GetObjGroupManager().GetAllGameObjPrefabs();
        _DrawSelectionForObjects(tmp_go_prefs, ref currBlocksIndexChoose, ref currBlockToPaint);

        if (currBlockToPaint != null)
        {
            Undo.RecordObject(objGroupManager, "Set ObjData");
            Undo.RecordObject(editorDataManager, "Set Editor");

            var objData = objGroupManager.GetObjSettingData(currBlocksIndexChoose);
            //是否增加偏移值
            objData.objDeltaPosY = EditorGUILayout.FloatField("Obj delta position_Y: ", objData.objDeltaPosY);
            objData.rateWhenDrag = EditorGUILayout.IntField("Generate rate when drag: ", objData.rateWhenDrag);

            //设置是否旋转方向：
            objData.randRotateDirection = (RAND_ROTATE_DIRECTION)EditorGUILayout.EnumPopup("Rand rotation:", objData.randRotateDirection);

            if ((objData.changeScale = EditorGUILayout.Toggle("Change it's scale", objData.changeScale)) == true)
            {
                EditorGUILayout.MinMaxSlider(string.Format("Change scale range({0:F1}~{1:F1}):", objData.changeScaleMin, objData.changeScaleMax),
                                             ref objData.changeScaleMin, ref objData.changeScaleMax, 0, 10);
                GUILayout.BeginHorizontal();

                EditorGUILayout.LabelField("Scale range: ");
                objData.changeScaleMin = EditorGUILayout.FloatField(objData.changeScaleMin);
                objData.changeScaleMax = EditorGUILayout.FloatField(objData.changeScaleMax);
                if (objData.changeScaleMin > objData.changeScaleMax)
                {
                    objData.changeScaleMax = objData.changeScaleMin;
                }

                GUILayout.EndHorizontal();


            }

            //是否更改父物体（需要自行注意递归式的悬挂，后期可去掉）
            _DrawChangeAttachParent(editorDataManager);


            #region Pick & Draw Info 
            EditorGUILayout.LabelField("Click to paint game object.");
            EditorGUILayout.LabelField("Hold Ctrl + Drag to paint game object.");
            EditorGUILayout.LabelField("Hold Shift + Click to erase a block.");
            #endregion
        }
        else
        {
            #region clear tool
            //if(GUILayout.Button("Clear all details"))
            //{
            //    manager.GetComponent<SceneObjAutoDisable>()
            //}
            #endregion
        }

        GUILayout.Space(16);
        #endregion

        #region Batch setting
        if (currBlockToPaint != null)
        {
            GUILayout.Label("BATCH SETTING:");
            GUILayout.Label("--This will generate many objs \nbase on following settings:");

            editorDataManager.batch_terrainTarget = (Terrain)EditorGUILayout.ObjectField("Generate on terrain: ", editorDataManager.batch_terrainTarget, typeof(Terrain), true);

            GUILayout.Label("Generate range:");
            editorDataManager.batchGenerateRangeX = EditorGUILayout.FloatField("RangeX:",editorDataManager.batchGenerateRangeX);
            editorDataManager.batchGenerateRangeZ = EditorGUILayout.FloatField("RangeZ:",editorDataManager.batchGenerateRangeZ);

            editorDataManager.batch_generateCount_Min = EditorGUILayout.IntField("Count min: ", editorDataManager.batch_generateCount_Min);
            editorDataManager.batch_generateCount_Max = EditorGUILayout.IntField("Count max: ", editorDataManager.batch_generateCount_Max);

            if (GUILayout.Button("Batch generate!",GUILayout.MaxWidth(128) )) 
            {
                if (editorDataManager.batch_terrainTarget == null)
                {
                    Debug.LogError("No target terrain specified.");
                }
                else
                {
                    editorDataManager.Editor_GetSceneObjGroup().Editor_BatchGenerateObjs(editorDataManager,objGroupManager.GetObjSettingData(currBlocksIndexChoose));

                }
            }
            GUILayout.Space(16);

            #region 在此基础上再散落生成多个组：
            GUILayout.Label("Group batch:");
            GUILayout.Label("--Clone group like this one on the terrain.");
            editorDataManager.groupbatch_groupNamePrefix= EditorGUILayout.TextField("Clone group name:", editorDataManager.groupbatch_groupNamePrefix);
            editorDataManager.groupbatch_groupNameIndexPostfix= EditorGUILayout.IntField("name postfix start from:", editorDataManager.groupbatch_groupNameIndexPostfix);
            editorDataManager.groupbatch_groupGenerateRangeX = EditorGUILayout.IntField("group range x:", editorDataManager.groupbatch_groupGenerateRangeX);
            editorDataManager.groupbatch_groupGenerateRangeZ = EditorGUILayout.IntField("group range z:", editorDataManager.groupbatch_groupGenerateRangeZ);
            editorDataManager.groupbatch_groupCount = EditorGUILayout.IntField("Clone group count:" , editorDataManager.groupbatch_groupCount);
            if(GUILayout.Button("Generate Group!",GUILayout.MaxWidth(128)))
            {
                BatchGenerateGroups();
            }

            #endregion

        }
        #endregion

        #region Tools
        GUILayout.Space(16);
        GUILayout.Label("3. Serilizing Tool:");

        GUILayout.Label("This will serialize details obj\nRequires [SceneObjAutoDisable]" );

        GUILayout.BeginHorizontal();
        if (GUILayout.Button("Serialize Details"))
        {
            editorDataManager.Editor_GetSceneObjGroup().Editor_SerializePrefabObjs();
        }
        
        if(GUILayout.Button("Serialize All"))
        {
            var allScripts = GetAllSceneObjsAutoDisable();
            for (int i = 0; i < allScripts.Length;i++)
            {
                allScripts[i].Editor_SerializePrefabObjs();
            }

            Debug.Log("All serialized to " +FileHelper.GetResourcesPath(Game.SceneObjGroup.C_DetailsPathInRes));
        }
        GUILayout.EndHorizontal();


        GUILayout.BeginHorizontal();
        if (GUILayout.Button("Delete Details"))
        {
            editorDataManager.Editor_GetSceneObjGroup().Editor_DeleteAllObjs();
        }

        if (GUILayout.Button("Delete All"))
        {
            if (EditorUtility.DisplayDialog("Confirm?","Delete all objects with <" + typeof(SceneObjGroup).Name + ">?","Yes"))
            {
                var allScript = GetAllSceneObjsAutoDisable();
                for (int i = 0; i < allScript.Length; i++)
                {
                    allScript[i].Editor_DeleteAllObjs();
                }
            }
        }

        GUILayout.EndHorizontal();

        GUILayout.BeginHorizontal();
        if(GUILayout.Button("Load Details Test"))
        {
            editorDataManager.Editor_GetSceneObjGroup().Editor_LoadObjsFromSerializedInfo();
        }

        if(GUILayout.Button("Load All Test"))
        {
            var allScript = GetAllSceneObjsAutoDisable();
            for (int i = 0; i < allScript.Length; i++)
            {
                allScript[i].Editor_LoadObjsFromSerializedInfo();
            }
        }

        GUILayout.EndHorizontal();
        #endregion

        #region TEST REGION
        //if(GUILayout.Button("TEST"))
        //{
            
        //    //var defaultConfig = UConfig.DefaultConfig;

        //    //Debug.Log("IS:" + defaultConfig.GetValue<int>("SHIT"));
        //}

        #endregion

    }

    private void BatchGenerateGroups()
    {
        if (editorDataManager.batch_terrainTarget == null)
        {
            Debug.LogError("No target terrain specified yet.");
        }

        int batchGroupIndex = editorDataManager.groupbatch_groupNameIndexPostfix;
        //生成组的范围参数
        int batchGroupRangeX = editorDataManager.groupbatch_groupGenerateRangeX;
        int batchGroupRangeZ = editorDataManager.groupbatch_groupGenerateRangeZ;
        //是否更改生成组的范围
        bool alterGenGroupRange = batchGroupRangeX > 0 && batchGroupRangeZ > 0;
        //地形
        var terrainTarget = editorDataManager.batch_terrainTarget;
        //随机生成组的位置
        Vector3 randPos;

        for (int i = 0; i < editorDataManager.groupbatch_groupCount; i++)
        {
            //生成组管理物体：
            GameObject groupMgr = Instantiate(this.editorDataManager.gameObject);
            Undo.RegisterCreatedObjectUndo(groupMgr, "Batch Create");

            groupMgr.name = this.editorDataManager.groupbatch_groupNamePrefix + (batchGroupIndex);
            batchGroupIndex++;

            //groupMgr.AddComponent <Editor_ObjDataManager> ();
            //groupMgr.AddComponent<SceneObjAutoDisable>();

            //代理物体：删掉之前的，替换为空物体：
            Transform preObj = groupMgr.transform.GetChild(0);
            DestroyImmediate(preObj.gameObject);

            GameObject detailsDelegate = new GameObject("DetailsGroup");
            detailsDelegate.transform.SetParent(groupMgr.transform);

            //--新的group的随机位置
            if (alterGenGroupRange)
            {
                //--同样需要迁移一半的位置，才能以此物体为中心
                var genSrcPosition = this.editorDataManager.transform.position;
                genSrcPosition.x -= 0.5f* batchGroupRangeX;
                genSrcPosition.z -= 0.5f * batchGroupRangeZ;
                randPos = TerrainHelper.GenerateRandomPosition(terrainTarget, genSrcPosition, batchGroupRangeX, batchGroupRangeZ);
            }
            else
            {
                randPos = TerrainHelper.GenerateRandomPosition(terrainTarget);
            }
        
            groupMgr.transform.position = randPos;

            //--以该group为设定数据源，进行批量的物体生成
            var dataMgr = groupMgr.GetComponent<Editor_ObjData>();
            var objScript = dataMgr.Editor_GetSceneObjGroup();
            //TODO: HOW TO//--换掉组目标：
            dataMgr.newObjParent = detailsDelegate;
            objScript.Editor_BatchGenerateObjs(dataMgr, objGroupManager.GetObjSettingData(currBlocksIndexChoose));

            //--设定这个脚本的AutoDisable的id
            objScript.Editor_ResetId();
        }
        editorDataManager.groupbatch_groupNameIndexPostfix = batchGroupIndex;
    }

    /// <summary>
    /// 是否更改生成的物体的Parent物体
    /// </summary>
    private void _DrawChangeAttachParent(Editor_ObjData manager)
    {
        if ((manager.changeNewObjParent = EditorGUILayout.Toggle("Change it's parent", manager.changeNewObjParent)) == true)
        {
            manager.newObjParent = (GameObject)EditorGUILayout.ObjectField("Change attach to:", manager.newObjParent, typeof(GameObject), true);
        }


        #region 输出子物体的数目
        Transform dianosParent = manager.newObjParent.transform;
        GUILayout.Label("Current children count: " + dianosParent.childCount );
        #endregion


    }

    /// <summary>
    /// 为游戏物体数组填充绘制一个选择列表框，并返回选择序号。如果选中为空，或超出范围，则返回空物体；
    /// </summary>
    /// <param name="go_prefs">将绘制的游戏物体栏</param>
    /// <param name="whichIndex">返回/引用的数组下标，用于存储当前选择的序号</param>
    /// <param name="pickToGO">用于存储选择的物品</param>
    /// <returns>返回选中的游戏物体</returns>
    private GameObject _DrawSelectionForObjects(GameObject[] go_prefs, ref int whichIndex, ref GameObject pickToGO)
    {
        Texture2D[] previews = GetPreviewsFromAssets(go_prefs);
        
        //计算行数，以计算行高
        int rows = ((previews.Length - 1) / 3) + 1;                      //减1以得正常整除，加1以得行数

        whichIndex = GUILayout.SelectionGrid(whichIndex, previews, 3, GUILayout.Height((rows > 0 ? rows : 1) * 64), GUILayout.Width(200), GUILayout.ExpandWidth(true));

        if ((whichIndex >= go_prefs.Length)                                     //id 越界
            || (whichIndex >= 0 && go_prefs[whichIndex] == null))//id正常，但是选的是null
        {
            whichIndex = -1;
        }

        //判断是否返回该物体：（如果选中了有效的物体，且不是之前选的）
        if (whichIndex != -1 )
        {
            pickToGO = go_prefs[whichIndex];
        }
        else
        {
            pickToGO = null;
        }

        //返回选中的游戏物体
        return pickToGO;
    }

    /// <summary>
    /// 获得物体prefab的预览图
    /// </summary>
    private Texture2D[] GetPreviewsFromAssets(GameObject[] s)
    {
        Texture2D[] pres = new Texture2D[s.Length];
        for (int i = 0; i < s.Length; i++)
        {
            pres[i] = AssetPreview.GetAssetPreview(s[i]);
        }
        return pres;
    }

    /// <summary>
    /// 给出一段空白空间
    /// </summary>
    private void _DrawEndSpace()
    {
        //----End----
        GUILayout.Space(32);
    }

    /// <summary>
    /// 在场景之中编辑地图、更新场景视图
    /// </summary>
    /// <param name="sceneView"></param>
    private void OnMapEditorSceneUpdate(SceneView sceneView)
    {
        //Prevent mouse click:
        Event e = Event.current;
        //if (manager.m_toolStatus != Editor_ObjDataManager.ToolStatus.BATCH_TOOL)
        {
            HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));
        }

        bool respondClick = true;                                                  //本次是否响应鼠标事件

        if (currBlockToPaint == null)
        {
            return;
        }

        //如果是要截取鼠标点击事件：
        if (respondClick)
        {
            //在场景视图点击处理：
            if (e.button == 0 &&
                (e.type == EventType.MouseDown || (e.type == EventType.MouseDrag)))
            {
                //旋转视图的情况下，不予以点击
                if (e.alt)
                {
                    return;
                }

                //再行判断是否按下了Shift键
                if (e.shift)
                {
                    //擦除物体：
                    EraseBlock(e.mousePosition,currBlockToPaint.tag);
                }
                else
                {
                    
                    //加了control的情况下，才允许拖动操作
                    if (e.type == EventType.MouseDrag )
                    {
                        if(e.control )
                        {
                            var settingData = objGroupManager.GetObjSettingData(currBlocksIndexChoose);
                            //如果拖动，又有生成概率的话，如果不在概率内，则拒绝生成
                            if(UnityEngine.Random.Range(0,100) > settingData.rateWhenDrag)
                            {
                                return;
                            }
                        }
                        else
                        {
                            return;
                        }
                    }
                    
                    DoCreateGridObj(e.mousePosition,
                                                           currBlocksIndexChoose, 
                                                           editorDataManager,
                                                           objGroupManager,
                                                            e.control);

                }
            }
            else if (e.button == 1 && e.type == EventType.MouseDown && e.control)
            {

                //已注释的Log( " -0.5:" + Mathf.RoundToInt( -1.2F) );
            }

        }

    }

    private bool IsPaintIn2DMap()
    {
        return (
            (Camera.current.orthographic)                                                    //正交视图
            && (Camera.current.transform.rotation == Quaternion.identity)
            );   //并且对准了xy平面
    }

    /// <summary>
    /// 创建网格内的游戏物体
    /// </summary>
    private static void DoCreateGridObj(Vector2 mousePos,int objDataIndex , Editor_ObjData manager,SceneObjGroupManager objGroupManager,  bool isControllDown = false)
    {
        var objDataSetting = objGroupManager.GetObjSettingData(objDataIndex);
        GameObject targetObjPref = objDataSetting.prefabObj;
        if (targetObjPref == null)
        {
            //新注释的Debug.Log( "No Prefab choose..." );
            return;
        }
        //--即将绘制的物体的tag（目前在创建中无用）
        string targetObjTag = targetObjPref.tag;

        //探测是否已经有砖块( 2D / 3D )
        
        Vector3 tmpPos = Vector3.zero;

        //创建位置（注意这里是对的是中心的位置，需要加上偏移才能正确定为左下角的位置）
        bool canGenerate = false;
        //Debug.Log("Target tag:"+manager.targetObjTagToPaintOn);
        tmpPos = Get3DHitPos(mousePos,  manager.targetObjTagToPaintOn, ref canGenerate);

        if (!canGenerate)
        {
            //射线未有碰到目标物体
            return;
        }


        //创建一个新的物体并保持prefab链接
        GameObject go = (GameObject)PrefabUtility.InstantiatePrefab(targetObjPref);
        go.transform.position = tmpPos;

        manager.Editor_GetSceneObjGroup().SetNewObjAcordingToSetting(go,manager.newObjParent.transform,objDataSetting);
        
    }

    /// <summary>
    /// 擦除砖块
    /// </summary>
    private static void EraseBlock(Vector2 mousePos, string targetTag)
    {
        //选择视图中的物体，并且选择其所在prefab的节点（而不选择最顶上的父节点）
        GameObject testObj = HandleUtility.PickGameObject(mousePos, true);
        
        if (testObj != null && testObj.CompareTag(targetTag))
        {
            Undo.DestroyObjectImmediate(testObj);
        }
    }

    /// <summary>
    /// 辅助函数，用于获得鼠标所点击在目标物体上的3D/2D空间位置
    /// </summary>
    private static Vector3 Get3DHitPos(Vector2 mousePos,string tagToHit, ref bool canGenerate)
    {
        Vector3 resultPos = Vector3.zero;
        Camera currCam = Camera.current;
        canGenerate = false;

        //对于无碰撞体在前的物体，先行排除：
        GameObject testObj = HandleUtility.PickGameObject(mousePos, true);
        if(false ==testObj.CompareTag(tagToHit))
        {
            canGenerate = false;
            return resultPos;
        }

        //射线判断有碰撞体的物体，并获得碰撞的位置：
        Ray ray = currCam.ScreenPointToRay(ConvertMousePosToScreenPos(mousePos));
        RaycastHit hit;
        
        if (Physics.Raycast(ray, out hit))
        {
            if (hit.transform.CompareTag(tagToHit))
            {
                //已注释的Log( "hit my plane" );
                resultPos = hit.point;

                canGenerate = true;
            }
        }

        return resultPos;
    }

    /// <summary>
    /// 鼠标位置转为屏幕位置（两者Y轴不同）
    /// </summary>
    /// <returns></returns>
    private static Vector3 ConvertMousePosToScreenPos(Vector2 mousePos)
    {
        mousePos.y = Camera.current.pixelHeight - mousePos.y;
        return mousePos;
    }

    /// <summary>
    /// 获得场景中所有该脚本
    /// </summary>
    /// <returns>The all scene objects auto disable.</returns>
    private Game.SceneObjGroup[] GetAllSceneObjsAutoDisable()
    {
        return GameObject.FindObjectsOfType<Game.SceneObjGroup>();
    }


    enum AlignOperation { NOPE, FitToGrid, AlignToBottom, AlignToCenter };

}
#endif